//
//  WmcMultimediaRequest.swift
//  YPWatermarkCamera
//
//  Created by 赵新 on 2022/5/27.
//

import Moya
import UIKit
import Alamofire
import YPBedrock
import YPNetwork
import KeychainAccess
import YPSignature

#if canImport(WmcLogin)
import WmcLogin
#endif

// MARK: - [WmcMediaRequest]

/*
 多媒体四套环境域名地址：
 开发：https://yupao-develop.vrtbbs.com
 测试：https://yupao-test.yupaowang.com
 预发布：https://yupao-master.yupaowang.com
 生产：https://yupao-prod.yupaowang.com
 */

class WmcMediaRequest: YPNetworkRequest {
    // Public

    /// !!!: 预留控制
    public var reservedFlag = true

    // Internal

    override var host: String {
        var text = "https://yupao-prod.yupaowang.com"
        let environmentType = YPWmcManager.shared.environmentType
        switch environmentType {
        case .develop:
            text = "https://yupao-develop.vrtbbs.com"
        case .test:
            text = "https://yupao-test.yupaowang.com"
        case .pre_release:
            text = "https://yupao-master.yupaowang.com"
        case .release:
            text = "https://yupao-prod.yupaowang.com"
        }
        return text
    }

    override var clientInfo: [String: String] {
        var channel = "AppStore"
        #if DEBUG
        channel = "Debug"
        #endif
        var header: [String: String] = [
            // 这些字段接口文档里没有，也不知道还要不要
            "appId": YPWmcManager.shared.appId, // 业务id
            "source": YPWmcManager.shared.platform.info.sourceField, // 来源
            "platform": "ios", // 平台
            "system": "IOS", // 系统类型
            "appVersion": YPApp.Version, // app应用版本
            "wmcVersion": YPWmcManager.shared.version, // 水印相机应用版本
            "systemVersion": UIDevice.current.systemVersion, // 操作系统版本

            // 新的接口文档：https://w3nu1yaadv.feishu.cn/wiki/wikcnLJEaiaUnob6aKEqTtA4Muh
            "os": "IOS",
            "runtime": "IOS",
            "business": YPWmcManager.shared.platform.info.business,
            "packagename": YPApp.Identifier,
            "channel": channel, // 渠道包
            "osversion": UIDevice.current.systemVersion,
            "runtimeversion": "UIDevice.current.systemVersion",
            "packageversion": YPWmcManager.shared.version,
            "brand": "Apple",
            "model": phoneModel,
            "advertisingid": "",
            "imei": Self.uuid,
            "deviceid": Self.uuid,
            "devicename": UIDevice.current.name,
            "sdkVersion": YPWmcManager.shared.mediaSdkVersion, // 多媒体SDK版本
        ]
        
        header.merge(YPWmcManager.shared.mediaExtensionHeaders, uniquingKeysWith: {$1})
        
        return header
    }

    override var userInfo: [String: String] {
        var result: [String: String] = [:]
        if let yupaoAccountModel = WmcLoginManager.shared.yupaoAccountModel, let wmcAccountModel = WmcLoginManager.shared.wmcAccountModel {
            result["token"] = yupaoAccountModel.token // 用户登录态token
            result["wmcToken"] = wmcAccountModel.token
        }

        return result
    }

    override var responseField: [YPNetworkRespnseField: String] {
        return [
            .messageField: "message",
            .codeField: "code",
            .modelField: "data",
            .listField: "list",
        ]
    }

    override var successInterceptor: YPNetworkInterceptor {
        return YPNetworkInterceptor.create(type: .success, code: [0])
    }

    override var loginFailureInterceptor: YPNetworkInterceptor? {
        return YPNetworkInterceptor.create(type: .loginFailure, code: [401]) { (data: Any?, code: Int64, message: String?) in
            WmcLoginManager.logout()
            YPWmcManager.shared.delegate.loginDelegate?.loginInvalid(.current, data: data, code: code, message: message)
        }
    }

    override var customInterceptors: [YPNetworkInterceptor]? {
        return [interimManagementInterceptor, removeFromTeamInterceptor, userSqueezedOutInterceptor]
    }

    /// 用户被挤掉（其他手机登录）
    private let userSqueezedOutInterceptor = YPNetworkInterceptor.create(type: .custom, code: [401], callback: { (data: Any, code: Int64, message: String?) in
        #if canImport(WmcLogin)
        YPLoginManager.shared.isSqueezedOut = true
        #endif
    })

    /// 上传时被踢出团队的错误码拦截器
    private let interimManagementInterceptor = YPNetworkInterceptor.create(type: .custom, code: [40003], callback: { (data: Any, code: Int64, message: String?) in
        guard let msg = message else { return }
        let alertController = UIAlertController(title: "上传失败提示", message: message, preferredStyle: .alert)
        let sureAction = UIAlertAction(title: "我知道了", style: .default, handler: nil)
        alertController.addAction(sureAction)
        YPApp.CurrentVC?.navigationController?.present(alertController, animated: true, completion: nil)
    })

    /// 被踢出团队
    private let removeFromTeamInterceptor = YPNetworkInterceptor.create(type: .custom, code: [40002], callback: { (data: Any, code: Int64, message: String?) in
        guard let currentVC = YPApp.CurrentVC as? WmcBaseVC else { return }
        if let currentVC = currentVC as? WmcPresentVC {
            if currentVC.config.contentView is WmcManualAddTeamMemberAlert {
                return
            }
        }
        WmcManualAddTeamMemberAlert.alertView(title: "您已被移除该团队", content: "可联系管理员重新加入", btnTitle: "我知道了", confirmB: {
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "com.watermark.removeFromTeam"), object: nil)
        }).show()
    })

    override var willSendRequest: (() -> Void)? {
        return { [weak self] in
            guard let weakSelf = self else { return }

            var params: [String: Any] = [:]

            // 如果url中带参数，将参数解析出来，合并到params
            if let url = URL(string: "\(weakSelf.host)\(weakSelf.path)"),
               let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
               let queryItems = components.queryItems {
                let dict: [String: Any]? = queryItems.reduce(into: [String: String]()) { (result, item) in
                    result[item.name] = item.value
                }

                if let dict = dict {
                    params.merge(dict) { (_, new) -> Any in new }
                }
            }

            // 将请求的参数合并到params
            if let dict = weakSelf.parameters {
                params.merge(dict) { (_, new) -> Any in new }
            }
            
            var date = Date()
            if let networkDate = WmcDateManager.shared.networkDate.value {
                date = networkDate
            }
            
            let signatureResult = YPSignature.generate(parameters: params, time: date, key: "8k&^$Hsk1?kkcj12^99K1ia")
                        
            weakSelf.extraHeaderFields = [
                "timestamp": "\(signatureResult.timestamp)",
                "nonce": "\(signatureResult.nonce)",
                "sign": signatureResult.signature,
                "signversion": "1",
            ]

            // 修改请求参数
            if let dict = weakSelf.parameters {
                weakSelf.task = Task.requestParameters(parameters: dict, encoding: JSONEncoding.default)
            } else {
                weakSelf.task = Task.requestParameters(parameters: [:], encoding: JSONEncoding.default)
            }
        }
    }

    // Fileprivate

    /// 日志系统
    fileprivate func log(_ log: String) {
        WmcLogManager.DebugLog(type: .mediaRequest, log: log)
    }

    // Private

    static var uuid: String = {
        let key = "uuid"
        guard let info = Bundle.main.infoDictionary else { return "" }
        guard let identifier = info["CFBundleIdentifier"] as? String else { return "" }

        let keychain = Keychain(service: identifier)
        guard let uuid = keychain[key] else {
            let uuid: String? = UIDevice.current.identifierForVendor?.uuidString
            keychain[key] = uuid
            return uuid ?? "无UUID"
        }
        return uuid
    }()

    private var phoneModel: String {
        var systemInfo = utsname()
        uname(&systemInfo)
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        let identifier = machineMirror.children.reduce("") { identifier, element in
            guard let value = element.value as? Int8, value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }
        return identifier
    }

    private func convertSpecialCharacter(_ valueDict: [String: Any]) -> [String: Any] {
        var valueDict = valueDict
        /*
         这里签需要注意:
         1.本质上最终会形成一个类似于url的东西:key1=value1&key2=value2
         2.value中大部分是自动生成,小部分是用户自定义,而用户自定义则可能出现特殊字符,需要转义
         3.在普通的key1=value1,value1为string的情况,特殊字符不需要转义.例如:address="四川成都\"
         4.在特殊的key1=value1,value1为json的情况下,特殊字符需要转义.例如:location={"addres:四川成都\\"}
         */
        for (key, value) in valueDict {
            if let vDict = value as? [String: Any] {
                var resultDict = convertSpecialCharacter(vDict)
                for (k, v) in resultDict {
                    if let str = v as? String {
                        resultDict[k] = dealSpecialCharacter(str)
                    }
                }
                valueDict[key] = resultDict
            }
            if var vArray = value as? [[String: Any]] {
                for (idx, item) in vArray.enumerated() {
                    let resultDict = convertSpecialCharacter(item)
                    vArray[idx] = resultDict
                }
                valueDict[key] = vArray
            } else if let str = value as? String, key == "content" {
                // 这里只针对备注:content
                let string = dealSpecialCharacter(str)
                valueDict[key] = string
            }
        }
        return valueDict
    }

    private func dealSpecialCharacter(_ str: String) -> String {
        // 这里本质上处理的是转义.因为content内容是用户输入,所以如果遇上特殊字符,必须转义.
        // 转义字符是由c定义的,但并不是所有的转义字符,语言级都支持.不同的语言支持的也不太一样
        // 这里顺序不能变,优先给斜线增加转义.
        // 响铃\a,退格\b,换页\f,垂直制表\v似乎iOS未支持这几类转义

        var string = str
        // 斜杆
        string = string.replacingOccurrences(of: "\\", with: "\\\\")
        // 换行
        string = string.replacingOccurrences(of: "\n", with: "\\n")
        // 双引号
        string = string.replacingOccurrences(of: "\"", with:
            """
            \\"
            """)
        // 单引号
        string = string.replacingOccurrences(of: "\'", with: "\\'")
        // 回车(CR)
        string = string.replacingOccurrences(of: "\r", with: "\\r")
        // 水平制表(HT)
        string = string.replacingOccurrences(of: "\t", with: "\\t")
        // 空字符(NULL)
        string = string.replacingOccurrences(of: "\0", with: "\\0")
        return string
    }
}
